package com.usooft.metaTalent.core.utils;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.fastjson.JSON;
import com.usooft.metaTalent.core.enums.TemplateEnums;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
public class ExcelEasyUtil {

    private static final String redis_excel_prefix = "redis:excel:prefix";

    /**
     * 同步读取文件 返回list 泛型Object  对应一行所有列数据。
     *
     * @param filePath 文件绝对路径
     * @return List<Object>
     */
    public static List<Object> getListByFile(String filePath) {
        return EasyExcel.read(filePath).sheet().doReadSync();
    }

    /**
     * 同步读取文件 返回list 泛型Object  对应一行所有列数据。
     *
     * @param in 文件输入流
     * @return List<Object>
     */
    public static List<Object> getListByInputStream(InputStream in) {
        return EasyExcel.read(in).sheet().doReadSync();
    }

    /**
     * 同步读取文件 返回list 泛型Object  对应一行所有列数据。
     *
     * @param filePath      文件绝对路径
     * @param templateClass 模板类
     * @return List<Object>
     */
    public static <T> List<T> getListByFile(String filePath, Class<T> templateClass) {
        return EasyExcel.read(filePath).head(templateClass).sheet().doReadSync();
    }

    /**
     * 同步读取文件 返回list 泛型Object  对应一行所有列数据。
     *
     * @param in            文件输入流
     * @param templateClass 模板类
     * @return List<Object>
     */
    public static <T> List<T> getListByInputStream(InputStream in, Class<T> templateClass) {
        return EasyExcel.read(in).head(templateClass).sheet().doReadSync();
    }


    /**
     * 将错误信息存入redis
     *
     * @param list          需要存储的数据list
     * @param templateClass list的class对象
     * @param userGh        当前用户工号
     * @return boolean
     */
    public static List<?> writeInRedis(List<?> list, Class templateClass, String userGh) {

        RedisTemplate redisTemplate = SpringContextHolder.getBean("redisTemplate", RedisTemplate.class);
        RedisSerializer redisSerializer = new StringRedisSerializer();

        redisTemplate.setHashKeySerializer(redisSerializer);
        redisTemplate.setHashValueSerializer(redisSerializer);


        redisTemplate.opsForValue().set(redis_excel_prefix + ":" + userGh, JSON.toJSONString(0));
        redisTemplate.opsForValue().set(redis_excel_prefix + ":" + userGh, JSON.toJSONString(list), 7, TimeUnit.DAYS);

        return checkInsert(redisTemplate, userGh, list, templateClass);
    }


    public static List<?> checkInsert(RedisTemplate redisTemplate, String userGh, List<?> list, Class templateClass) {
        List<?> listMsg = null;
        String res = (String) redisTemplate.opsForValue().get(redis_excel_prefix + ":" + userGh);

        if (StringUtils.isNotBlank(res)) {
            listMsg = JSON.parseArray(res, templateClass);

            return listMsg;
        } else {
            for (int i = 0; i < 10; i++) {
                redisTemplate.opsForValue().set(redis_excel_prefix + ":" + userGh, JSON.toJSONString(list), 7, TimeUnit.DAYS);
                String result = (String) redisTemplate.opsForValue().get(redis_excel_prefix + ":" + userGh);

                if (StringUtils.isNotBlank(result)) {
                    listMsg = JSON.parseArray(result, templateClass);
                    return listMsg;
                }
            }
        }
        return null;
    }


    /**
     * 一行一行读取完后 触发自己写的监听器  invoke函数每读完一行就执行一次，doAfterAllAnalysed函数每读完一个sheet 执行一次
     *
     * @param filePath
     * @param myListener
     */
    public static void getListByListener(String filePath, AnalysisEventListener myListener) {
        EasyExcel.read(filePath, myListener).sheet().doRead();
    }

    /**
     * 根据传输的url返回一个输入流
     */
    public static InputStream getStreamByUrl(String filePath) {
        HttpURLConnection conn = null;
        try {
            URL url = new URL(filePath);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(20 * 1000);
            final ByteArrayOutputStream output = new ByteArrayOutputStream();
            IOUtils.copy(conn.getInputStream(), output);
            return new ByteArrayInputStream(output.toByteArray());
        } catch (Exception e) {
            log.error(String.valueOf(e));
        } finally {
            try {
                if (conn != null) {
                    conn.disconnect();
                }
            } catch (Exception e) {
                log.error(String.valueOf(e));
            }
        }
        return null;
    }


    /**
     * 根据传入的文件路径返回对应的excel读取的list<bean>
     */
    public static <T> List<T> getListByFilePath(String filePath, Class<T> templateClass) {
        InputStream inputStream = getStreamByUrl(filePath);
        List<T> list = getListByInputStream(inputStream, templateClass);
        return list;
    }


    public static void writeStringListOut(List<List<String>> list, List<List<String>> model, ExcelTypeEnum type, OutputStream outPutStream) {
        EasyExcel.write(outPutStream).head(model).useDefaultStyle(false).excelType(type).sheet(0).doWrite(list);
    }

    public static void outputStreamExport(HttpServletResponse response, TemplateEnums templateEnums) throws IOException {
        OutputStream os = null;
        ClassPathResource classPathResource = new ClassPathResource(templateEnums.getFilePath());
        InputStream inputStream = classPathResource.getInputStream();
        response.reset();
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("utf-8");
        response.addHeader("Content-Disposition", String.format("attachment; filename=\"%s\"", URLEncoder.encode(templateEnums.getFileName(), StandardCharsets.UTF_8)));
        try (BufferedInputStream bis = new BufferedInputStream(inputStream)) {
            byte[] buff = new byte[1024];
            os = response.getOutputStream();
            int i = 0;
            while ((i = bis.read(buff)) != -1) {
                os.write(buff, 0, i);
                os.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            os.close();
        }
    }

    public static void export(List data, String fileName, Class objClass, ExcelTypeEnum type, HttpServletResponse response) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        fileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(response.getOutputStream(), objClass).useDefaultStyle(false).excelType(type).sheet(0).doWrite(() -> data);
    }

}
